﻿using System;
using System.Windows.Forms;
using CodeStash.Addin.Core;
using CodeStash.Addin.Resources;
using System.Diagnostics;
using CodeStash.Common.Helpers;
using CodeStash.Addin.Core.Interfaces;
using CodeStash.Addin.MEF;
using System.ComponentModel;

namespace CodeStash.Addin.PropertyPage
{
    public partial class CodeStashSettingsView : UserControl
    {
        private LoginDetails login;
        private ILoginDetails loginDetails;
        private BackgroundWorker bw;

        public CodeStashSettingsView()
        {
            InitializeComponent();

            loginDetails = MEFPartsResolver.Instance.Resolve<ILoginDetails>();
            login = loginDetails.Load();

            txtEmail.Text = login.EmailAddress;
            txtPassword.Text = login.Password;
            txtToken.Text = login.Token;

            // If the password is empty, default to the token being selected.
            rdoToken.Checked = !string.IsNullOrWhiteSpace(login.Password);
        }

        private void CheckedChanged(object sender, EventArgs e)
        {
            SetTextEnabledState(rdoToken.Checked);
        }

        /// <summary>
        /// Here we are going to set the enabled/disabled state of the text boxes based
        /// on the radio button. What we aren't going to do is remove the status of the
        /// text values - if the user changes the value, we shouldn't change this.
        /// </summary>
        /// <param name="tokenIsEnabled"></param>
        private void SetTextEnabledState(bool tokenIsEnabled)
        {
            txtToken.Enabled = tokenIsEnabled;
            txtPassword.Enabled = !tokenIsEnabled;

            btnSave.Enabled = CanSave();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            // OK, let's save the login details....
            login.EmailAddress = txtEmail.Text;
            if (rdoToken.Checked)
            {
                SetLoginPassInfo(txtToken.Text, string.Empty);
            }
            else
            {
                SetLoginPassInfo(string.Empty, txtPassword.Text);
            }

            bw = new BackgroundWorker();

            bw.DoWork += bw_DoWork;
            bw.RunWorkerCompleted += bw_RunWorkerCompleted;

            bw.RunWorkerAsync();
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            bw.DoWork -= bw_DoWork;
            bw.RunWorkerCompleted -= bw_RunWorkerCompleted;

            SaveResult result = (SaveResult)e.Result;
            switch (result)
            {
                case SaveResult.SaveFailed:
                    MessageBox.Show(Messages.SettingsFailed);
                    break;
                case SaveResult.SaveSuccessful:
                    MessageBox.Show(Messages.SettingsSaved);
                    break;
                case SaveResult.FailedToAuthenticate:
                    MessageBox.Show(Messages.UnableToAuthenticate);
                    break;
            }

            btnSave.Enabled = true;
        }

        private enum SaveResult
        {
            SaveSuccessful,
            SaveFailed,
            FailedToAuthenticate
        }

        void bw_DoWork(object sender, DoWorkEventArgs e)
        {

            // We will put a user test in here to see if we can connect.

            // 1st of all, attempt to connect to the CodeStash database.
            try
            {
                IRestService restService = MEFPartsResolver.Instance.Resolve<IRestService>();
                var canConnect = restService.CanConnectToCodeStash(login);

                if (!canConnect)
                {
                    e.Result = SaveResult.FailedToAuthenticate;
                    return;
                }
            }
            catch (Exception)
            {
                e.Result = SaveResult.FailedToAuthenticate;
                return;
            }

            e.Result = SaveDetails();
        }

        private SaveResult SaveDetails()
        {
            try
            {

                loginDetails.Save(login);
                return SaveResult.SaveSuccessful;
            }
            catch
            {
                return SaveResult.SaveFailed;
            }
        }

        private bool CanSave()
        {
            // While I could have combined these tests, for clarity sake
            // I have decided to leave them as separate tests. This way,
            // it's clearer what the tests actually are.
            if (string.IsNullOrWhiteSpace(txtEmail.Text))
            {
                return false;
            }
            if (rdoToken.Checked && string.IsNullOrWhiteSpace(txtToken.Text))
            {
                return false;
            }
            if (rdoPassword.Checked && string.IsNullOrWhiteSpace(txtPassword.Text))
            {
                return false;
            }

            return true;
        }

        private void SetLoginPassInfo(string openId, string password)
        {
            login.Token = openId;
            login.Password = password;
        }

        private void SettingsTextChanged(object sender, EventArgs e)
        {
            btnSave.Enabled = CanSave();
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            // Go to the CodeStash website.
            Process.Start(ConfigurationSettings.CodeStashWebAddress);
        }
    }
}
